﻿
namespace Patterns4Net.ArchitectureExplorer.ViewModels.Results
{
    using System;
    using System.ComponentModel.Composition;
    using System.Diagnostics.Contracts;
    using System.Threading;
    using Caliburn.Micro;
    using Patterns4Net.ArchitectureExplorer.Diagram;
    using Patterns4Net.ArchitectureExplorer.Diagram.Services;
    using Patterns4Net.ArchitectureExplorer.ViewModels.Messages;

    /// <summary>
    /// Represents an action which asynchronously loads an assembly into the diagram.
    /// </summary>
    /// <remarks>
    /// <para>Dependencies should be injected through properties.</para>
    /// </remarks>
    public class LoadAssembly : IResult
    {
        private readonly string filename;

        private readonly Diagram diagram;

        /// <summary>
        /// Initializes a new instance of the <see cref="LoadAssembly"/> class.
        /// </summary>
        /// <param name="filename">The filename of an assembly to be loaded.</param>
        /// <param name="diagram">The diagram into which the assembly should be added.</param>
        public LoadAssembly(string filename, Diagram diagram)
        {
            this.filename = filename;
            this.diagram = diagram;
        }

        /// <summary>
        /// Gets or sets the event aggregator instance.
        /// </summary>
        [Import]
        public IEventAggregator EventAggregator { get; set; }

        /// <summary>
        /// Gets or sets the diagram loading service.
        /// </summary>
        [Import]
        public IDiagramLoader DiagramLoader { get; set; }

        /// <summary>
        /// Gets or sets the output window, into which loading information are written.
        /// </summary>
        [Import]
        public OutputWindowViewModel OutputWindow { get; set; }

        /// <summary>
        /// For testing purposes.
        /// </summary>
        public string Filename
        {
            get { return this.filename; }
        }

        /// <summary>
        /// Executes the loading in a separate thread, when loading is finished 
        /// the <see cref="DiagramUpdatedMessage"/> is published.
        /// </summary>
        /// <remarks>
        /// <para>Publishing of messages using <see cref="IEventAggregator"/> should be thread safe.</para>
        /// </remarks>
        /// <param name="context">The context of the action. 
        /// It is required by base class method declaration, but not used.</param>
        public void Execute(ActionExecutionContext context)
        {
            Contract.Requires(this.EventAggregator != null);
            Contract.Requires(this.DiagramLoader != null);
            Contract.Requires(this.OutputWindow != null);

            new Thread(() =>
            {
                    this.DiagramLoader.Load(this.filename, this.diagram, this.OutputWindow.GetWriter());
                    this.EventAggregator.Publish(new DiagramUpdatedMessage(this.diagram));
                    if (this.Completed != null)
                    {
                        this.Completed(this, new ResultCompletionEventArgs { WasCancelled = false });
                    }
            }).Start();
        }

        /// <summary>
        /// Occurs when execution has completed.
        /// </summary>
        public event EventHandler<ResultCompletionEventArgs> Completed;
    }
}
